package com.topisv.tms.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.CusStockMerge;
import com.topisv.tms.entity.CustomerAreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.log.OrderLog;
import com.topisv.tms.mybatis.SqlMapDao;
import com.topisv.tms.repository.CusStockMergeDao;
import com.topisv.tms.repository.CustomerAreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.repository.EdiOrderItemDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.log.OrderLogDao;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.utils.enums.StatusEnums;

@Component
public class ResetOrderService extends BaseService {
	@Autowired
	private EdiOrderDao ediOrderDao;
	@Autowired
	private EdiOrderItemDao ediOrderItemDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private CusStockMergeDao cusStockMergeDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private OrderLogDao orderLogDao;
	@Autowired
	private CustomerAreaGroupDao customerAreaGroupDao;
	@PersistenceContext
	private EntityManager em;
	@Autowired
	private SqlMapDao sqlMapDao;

	/**
	 * 分页查询订单
	 * 
	 * @param param
	 * @param i
	 * @param pageSize
	 * @return
	 */
	public Page<EdiOrder> loadPageOrder(Map<String, Object> param, int pageNumber, int pageSize) {
		Sort sort = new Sort(Sort.Direction.DESC, "lastRestOrderTime").and(new Sort(Sort.Direction.DESC, "crtime"));
		PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize, sort);
		Specification<EdiOrder> spec = getWhereClause(param);
		Page<EdiOrder> page = ediOrderDao.findAll(spec, pageRequest);
		return page;
	}

	/**
	 * 查询条件封装
	 * 
	 * @param searchParams
	 * @return
	 */
	private Specification<EdiOrder> getWhereClause(final Map<String, Object> searchParams) {

		return new Specification<EdiOrder>() {

			@Override
			public Predicate toPredicate(Root<EdiOrder> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
				Predicate pre = cb.conjunction();

				// 作业网点
				String warehouseCode = (String) searchParams.get("warehouseCode");
				if (StringUtils.isNotBlank(warehouseCode)) {
					pre.getExpressions().add(cb.equal(r.get("warehouseCode"), warehouseCode));
				}

				// 快递公司
				String companyCode = (String) searchParams.get("companyCode");
				if (StringUtils.isNotBlank(companyCode) && !("-1".equals(companyCode)) && !("-2".equals(companyCode))
						&& !("-3".equals(companyCode))) {
					pre.getExpressions().add(cb.equal(r.get("cacode"), companyCode));
				} else if ("-2".equals(companyCode)) {
					Predicate[] companyCodesArray = new Predicate[3];
					companyCodesArray[0] = cb.isNull(r.get("cacode"));
					companyCodesArray[1] = cb.equal(r.get("cacode"), "");
					companyCodesArray[2] = cb.equal(r.get("cacode"), "OTHER");

					pre.getExpressions().add(cb.or(companyCodesArray));
				}

				// 商家
				String customerCode = (String) searchParams.get("customerCode");
				if (StringUtils.isNotBlank(customerCode)) {
					pre.getExpressions().add(cb.equal(r.get("customerCode"), customerCode));
				}
				// 创建时间
				Date fromDate = (Date) searchParams.get("fromDate");
				if (fromDate != null) {
					pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date> get("crtime"), fromDate));
				}

				Date toDate = (Date) searchParams.get("toDate");
				if (toDate != null) {
					pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date> get("crtime"), toDate));
				}

				// 作业状态
				String status = (String) searchParams.get("status");
				if (StringUtils.isNotBlank(status)) {
					pre.getExpressions().add(cb.equal(r.get("status"), status));
				}
				String dispatchFlag = (String) searchParams.get("dispatchFlag");
				if (StringUtils.isNotBlank(dispatchFlag)) {
					pre.getExpressions().add(cb.equal(r.get("dispatchFlag"), dispatchFlag));
				}
				// 订单状态
				String orderStatus = (String) searchParams.get("orderStatus");
				if (StringUtils.isNotBlank(orderStatus)) {
					pre.getExpressions().add(cb.equal(r.get("orderStatus"), orderStatus));
				}
				// 过滤B2BCK类型
				String deliveryOrderType = (String) searchParams.get("deliveryOrderType");
				if (StringUtils.isNotBlank(deliveryOrderType)) {
					pre.getExpressions().add(cb.notEqual(r.get("deliveryOrderType"), deliveryOrderType));
				}
				// 订单号
				String orderno = (String) searchParams.get("orderno");
				if (StringUtils.isNotBlank(orderno)) {
					pre.getExpressions()
							.add(cb.or(cb.equal(r.get("ordeno"), orderno.trim()),
									cb.equal(r.get("fromno"), orderno.trim()),
									cb.equal(r.get("customerOrdeno"), orderno.trim())));
				}
				// 商家组
				String customerCodes = (String) searchParams.get("customerCodes");
				if (StringUtils.isNotBlank(customerCodes)) {
					String[] customerCodeSplit = customerCodes.split(":");
					ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
					int i = 0;
					for (String _customerCode : customerCodeSplit) {
						tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
						i++;
					}
					pre.getExpressions().add(cb.or(tempCustomerCode));
				}

				// 仓库组
				String areagroups = (String) searchParams.get("areagroups");
				if (StringUtils.isNotBlank(areagroups)) {
					String[] areagroupSplit = areagroups.split(":");
					ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
					int j = 0;
					for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("warehouseCode"), _areagroup);
						j++;
					}
					pre.getExpressions().add(cb.or(areagroupArray));
				}

				pre.getExpressions().add(cb.equal(r.get("gymemo"), "1"));
				return pre;
			}
		};
	}

	/**
	 * 操作同一个商家、仓库锁定，
	 * 
	 * @param customerCode
	 * @param warehouseCode
	 * @param dateks
	 * @param datejs
	 * @param name
	 * @return
	 */
	@Transactional
	public boolean lock(String customerCode, String warehouseCode, Map<String, Date> dates, String name)
			throws Exception {
		String sql = "INSERT INTO reset_order_lock(customer_code, warehouse_code,start_day,end_day,operator,operated_time,status) "
				+ " SELECT ?, ?, ?, ?,?,?,? FROM DUAL "
				+ " WHERE NOT EXISTS (SELECT 1 FROM reset_order_lock WHERE customer_code=? and warehouse_code=? and status=?)";

		Query query = em.createNativeQuery(sql);
		int i = 1;
		query.setParameter(i++, customerCode);
		query.setParameter(i++, warehouseCode);
		query.setParameter(i++, dates.get("fromDate"));
		query.setParameter(i++, dates.get("toDate"));
		query.setParameter(i++, name);
		query.setParameter(i++, new Date());
		query.setParameter(i++, 1);
		query.setParameter(i++, customerCode);
		query.setParameter(i++, warehouseCode);
		query.setParameter(i++, 1);
		int count = query.executeUpdate();
		return count == 1 ? true : false;
	}

	/**
	 * 解锁同一个商家、仓库
	 * 
	 * @param customerCode
	 * @param warehouseCode
	 */
	@Transactional
	public void unlock(String customerCode, String warehouseCode) {
		String sql = "update reset_order_lock set status=?"
				+ " WHERE customer_code=? and warehouse_code=? and status=? ";

		Query query = em.createNativeQuery(sql);

		int i = 1;
		query.setParameter(i++, 2);
		query.setParameter(i++, customerCode);
		query.setParameter(i++, warehouseCode);
		query.setParameter(i++, 1);
		int cnt = query.executeUpdate();

	}

	/**
	 * 根据id查询订单
	 * 
	 * @param orderId
	 * @return
	 */
	public EdiOrder findOne(Long orderId) {
		if (orderId == null) {
			throw new IllegalArgumentException("orderId=" + orderId);
		}
		return ediOrderDao.findOne(orderId);
	}

	@Transactional(rollbackFor = Exception.class, readOnly = false)
	public boolean reUseEdiOrder(String id) throws Exception {
		EdiOrder ediOrders = this.findOne(Long.parseLong(id));
		List<EdiOrderItem> items = ediOrderItemDao.findByWaybillNo(ediOrders.getWaybillNo());
		Customers customers = customersDao.findByCustomerCode(ediOrders.getCustomerCode());
		Date nowDate = new Date();
		List<CusStockMerge> cusStockMergeList = new ArrayList<CusStockMerge>();
		// 检验订单状态以及明细
		if (checkOrder(ediOrders, items)) {
			// 判断订单流入是否限制
			if ("1".equals(customers.getPlaceStatus())) {
				// 根据订单明细中的SKU逐个检验库存
				cusStockMergeList = checkCusStockByEdiOrderItem(ediOrders, items);
				if (cusStockMergeList == null) {
					return false;
				}			
				cusStockMergeDao.save(cusStockMergeList);
			}
			// 更新订单状态
			ediOrders.setDispatchFlag("1");
			ediOrderDao.save(ediOrders);
			User user = userDao.findOne(getShiroUser().id);
			OrderLog orderLog = new OrderLog(ediOrders.getOrdeno(), ediOrders.getCustomerCode(), "0", null, new Date(),
					null, "批量接收订单");
			orderLog.setOperater(user);
			orderLogDao.save(orderLog);
			return true;
		}
		return false;

	}
	/**
	 *  检验订单状态以及明细
	 * @param ediOrders
	 * @param items
	 * @return
	 */
	private boolean checkOrder(EdiOrder ediOrders, List<EdiOrderItem> items) {
		if (items == null || items.isEmpty()
				|| StringUtils.equals(ediOrders.getOrderStatus(), StatusEnums.ORDER_STATUS_CANCEL.getStatus())
				|| StringUtils.equals(ediOrders.getDispatchFlag(), StatusEnums.ORDER_DISPATCHFLAG_YES.getStatus())) {
			return false;
		}
		return true;
	}
	/**
	 * 根据订单明细中的SKU逐个检验库存
	 * @param ediOrders
	 * @param items
	 * @return
	 * @throws Exception
	 */
	@Transactional(rollbackFor = Exception.class, readOnly = false)
	public List<CusStockMerge> checkCusStockByEdiOrderItem(EdiOrder ediOrders, List<EdiOrderItem> items) throws Exception {
		Date nowDate = new Date();
		String customerCode = ediOrders.getCustomerCode();
		String areagroupCode = ediOrders.getWarehouseCode();
		List<CusStockMerge> cusStockMergeList = new ArrayList<CusStockMerge>();
		Map<String,Object> paramMap = new HashMap<String,Object>();
		paramMap.put("customerCode", customerCode);
		paramMap.put("areagroupCode", areagroupCode);
		for (EdiOrderItem ei : items) {
			// 待拣货的商品数量
			int qty = ei.getQty();
			ei.setCrtime(nowDate);
			ediOrderItemDao.save(ei);
			ediOrders.setLastRestOrderTime(nowDate);
			ediOrderDao.save(ediOrders);
			paramMap.put("sku", ei.getSku());
	        List<CusStockMerge> list = sqlMapDao.selectList("cusStockMergeMapper.getCusStockMergeList", paramMap);
			//没有库存
	        if(list == null || list.isEmpty()){
	        	return null;
	        }
	        CusStockMerge cusStockMerge=list.get(0);
	        if(cusStockMerge.getId() == null){
	        	CusStockMerge tempCusStockMerge = new CusStockMerge();
				tempCusStockMerge.setCustomerCode(customerCode);
				tempCusStockMerge.setWarehouseCode(areagroupCode);
				tempCusStockMerge.setOrderNum(0);
				tempCusStockMerge.setSalesNum(0);
				tempCusStockMerge.setSku(ei.getSku());
				tempCusStockMerge.setVersion(0);
				tempCusStockMerge.setLastmodifyTime(nowDate);
				cusStockMergeDao.save(tempCusStockMerge);
				return null;
	        }
	        int needQty= cusStockMerge.getOrderNum() + qty; 
	        if(cusStockMerge.getStockSalesNum() < needQty){
	        	return null;
	        }else{
	        	CusStockMerge copyCusStockMerge = new CusStockMerge();
				BeanUtils.copyProperties(cusStockMerge,copyCusStockMerge);
				copyCusStockMerge.setOrderNum(needQty);
	        	cusStockMergeList.add(copyCusStockMerge);
	        } 
		}
		return cusStockMergeList;
	}

	
}
